<script setup>
import { ref, shallowRef, onMounted, onUnmounted } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';

// 使用shallowRef避免Three.js对象被深度响应式代理
const scene = shallowRef(null);
const camera = shallowRef(null);
const renderer = shallowRef(null);
const controls = shallowRef(null);
const model = shallowRef(null);
const canvas = ref(null);

// 使用ref用于响应式数据
const isLoading = ref(false);
const modelPosition = ref({ x: 0, y: 0, z: 0 });
const modelScale = ref(1);

// 初始化Three.js场景
const initScene = () => {
  // 创建场景
  scene.value = new THREE.Scene();
  scene.value.background = new THREE.Color(0x1a1a2e);
  scene.value.fog = new THREE.Fog(0x1a1a2e, 10, 20);
  
  // 创建相机
  camera.value = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.value.position.set(0, 2, 5);
  
  // 创建渲染器
  renderer.value = new THREE.WebGLRenderer({
    antialias: true,
    canvas: canvas.value
  });
  renderer.value.setSize(window.innerWidth, window.innerHeight);
  renderer.value.shadowMap.enabled = true;
  renderer.value.shadowMap.type = THREE.PCFSoftShadowMap;
  
  // 添加轨道控制器 - 修复：使用正确的OrbitControls导入方式
  controls.value = new OrbitControls(camera.value, renderer.value.domElement);
  controls.value.enableDamping = true;
  controls.value.dampingFactor = 0.05;
  
  // 添加灯光
  const ambientLight = new THREE.AmbientLight(0x404040, 0.8);
  scene.value.add(ambientLight);
  
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  directionalLight.position.set(5, 10, 7.5);
  directionalLight.castShadow = true;
  directionalLight.shadow.mapSize.width = 1024;
  directionalLight.shadow.mapSize.height = 1024;
  scene.value.add(directionalLight);
  
  // 添加网格地面
  const gridHelper = new THREE.GridHelper(10, 10, 0x00ff00, 0x444444);
  scene.value.add(gridHelper);
  
  const floorGeometry = new THREE.PlaneGeometry(10, 10);
  const floorMaterial = new THREE.MeshStandardMaterial({
    color: 0x222222,
    metalness: 0,
    roughness: 0.8
  });
  const floor = new THREE.Mesh(floorGeometry, floorMaterial);
  floor.rotation.x = -Math.PI / 2;
  floor.receiveShadow = true;
  scene.value.add(floor);
  
  // 添加坐标轴辅助
  const axesHelper = new THREE.AxesHelper(3);
  scene.value.add(axesHelper);
};

// 加载模型
const loadModel = (type = 'cube') => {
  isLoading.value = true;
  
  // 使用setTimeout模拟加载过程
  setTimeout(() => {
    // 移除旧模型（如果存在）
    if (model.value) {
      scene.value.remove(model.value);
    }
    
    // 加载FBX模型
    if (type === 'fbx') {
      const loader = new FBXLoader();
      
      // 加载FBX文件（注意路径需正确）
      loader.load(
        '/fbx001.fbx', // FBX文件路径
        (loadedModel) => { // 加载成功回调
          model.value = loadedModel;
          
          // 调整模型属性（根据实际模型大小调整）
          model.value.scale.set(0.01, 0.01, 0.01); // 缩放（多数FBX模型较大）
          model.value.position.set(0, 0.5, 0); // 位置（放在地面上）
          model.value.rotation.y = Math.PI; // 旋转（可选，根据模型朝向调整）
          
          // 启用阴影
          model.value.traverse((child) => {
            if (child.isMesh) {
              child.castShadow = true;
              child.receiveShadow = true;
            }
          });
          
          scene.value.add(model.value);
          updatePositionDisplay();
          isLoading.value = false;
        },
        (xhr) => { // 加载进度回调
          console.log(`加载进度: ${(xhr.loaded / xhr.total * 100).toFixed(2)}%`);
        },
        (error) => { // 加载错误回调
          console.error('FBX加载失败:', error);
          // 加载失败时创建一个默认模型
          const geometry = new THREE.BoxGeometry(1, 1, 1);
          const material = new THREE.MeshStandardMaterial({ 
            color: 0xff0000,
            metalness: 0.5,
            roughness: 0.2
          });
          
          model.value = new THREE.Mesh(geometry, material);
          model.value.castShadow = true;
          model.value.position.set(0, 0.5, 0);
          scene.value.add(model.value);
          
          updatePositionDisplay();
          isLoading.value = false;
        }
      );
      return; // 终止函数，避免执行后续几何体逻辑
    }
    
    let geometry;
    
    if (type === 'cube') {
      geometry = new THREE.BoxGeometry(1, 1, 1);
    } else if (type === 'sphere') {
      geometry = new THREE.SphereGeometry(0.7, 32, 32);
    } else if (type === 'torus') {
      geometry = new THREE.TorusGeometry(0.5, 0.2, 16, 100);
    } else if (type === 'cone') {
      geometry = new THREE.ConeGeometry(0.7, 1.5, 32);
    }
    
    const material = new THREE.MeshStandardMaterial({
      color: 0x4cc9f0,
      metalness: 0.5,
      roughness: 0.2
    });
    
    // 创建新模型
    model.value = new THREE.Mesh(geometry, material);
    model.value.castShadow = true;
    model.value.position.set(0, 0.5, 0);
    scene.value.add(model.value);
    
    // 更新位置显示
    updatePositionDisplay();
    
    isLoading.value = false;
  }, 1000);
};

// 更新模型位置显示
const updatePositionDisplay = () => {
  if (model.value) {
    modelPosition.value = {
      x: model.value.position.x.toFixed(2),
      y: model.value.position.y.toFixed(2),
      z: model.value.position.z.toFixed(2)
    };
  }
};

// 动画循环
const animate = () => {
  requestAnimationFrame(animate);
  if (controls.value) {
    controls.value.update();
  }
  if (renderer.value && scene.value && camera.value) {
    renderer.value.render(scene.value, camera.value);
  }
};

// 处理窗口大小变化
const onWindowResize = () => {
  if (camera.value && renderer.value) {
    camera.value.aspect = window.innerWidth / window.innerHeight;
    camera.value.updateProjectionMatrix();
    renderer.value.setSize(window.innerWidth, window.innerHeight);
  }
};

// 处理鼠标移动模型
const setupModelMovement = () => {
  const canvasElement = renderer.value.domElement;
  let isDragging = false;
  let previousMousePosition = {
    x: 0,
    y: 0
  };
  
  canvasElement.addEventListener('mousedown', (e) => {
    isDragging = true;
    previousMousePosition = {
      x: e.clientX,
      y: e.clientY
    };
  });
  
  canvasElement.addEventListener('mouseup', () => {
    isDragging = false;
  });
  
  canvasElement.addEventListener('mousemove', (e) => {
    if (!isDragging || !model.value) return;
    
    const deltaMove = {
      x: e.clientX - previousMousePosition.x,
      y: e.clientY - previousMousePosition.y
    };
    
    // 根据鼠标移动调整模型位置（仅在X和Y轴上移动）
    model.value.position.x += deltaMove.x * 0.01;
    model.value.position.y -= deltaMove.y * 0.01;
    
    // 确保Z轴始终为0
    model.value.position.z = 0;
    
    // 更新位置显示
    updatePositionDisplay();
    
    previousMousePosition = {
      x: e.clientX,
      y: e.clientY
    };
  });
};

// 调整模型大小
const updateModelScale = () => {
  if (model.value) {
    model.value.scale.set(modelScale.value, modelScale.value, modelScale.value);
  }
};

// 重置模型位置
const resetModelPosition = () => {
  if (model.value) {
    model.value.position.set(0, 0.5, 0);
    updatePositionDisplay();
  }
};

onMounted(() => {
  initScene();
  animate();
  window.addEventListener('resize', onWindowResize, false);
  
  // 初始加载一个模型
  loadModel();
  
  // 设置模型移动事件（需要在渲染器dom元素创建后调用）
  setTimeout(setupModelMovement, 100);
});

onUnmounted(() => {
  window.removeEventListener('resize', onWindowResize);
  if (renderer.value) {
    renderer.value.dispose();
  }
  if (controls.value) {
    controls.value.dispose();
  }
});
</script>

<template>
  <div class="container">
    <div class="canvas-container">
      <canvas ref="canvas" class="three-canvas"></canvas>
      <div v-if="isLoading" class="loading-overlay">
        <div class="spinner"></div>
        <div class="loading-text">加载模型中...</div>
      </div>
    </div>
    
    <div class="controls-panel">
      <div class="control-group">
        <h3>模型控制</h3>
        <div class="model-selector">
          <button class="btn model-btn" @click="loadModel('cube')">立方体</button>
          <button class="btn model-btn" @click="loadModel('sphere')">球体</button>
          <button class="btn model-btn" @click="loadModel('torus')">圆环</button>
          <button class="btn model-btn" @click="loadModel('cone')">圆锥</button>
          <button class="btn model-btn" @click="loadModel('fbx')">加载FBX</button>
        </div>
        
        <button class="btn" @click="resetModelPosition">重置位置</button>
        
        <div style="margin-top: 15px;">
          <label>模型大小: </label>
          <input type="range" min="0.5" max="2" step="0.1" v-model="modelScale" @input="updateModelScale">
          <span>{{ modelScale }}x</span>
        </div>
        
        <div class="position-display">
          <div>X: <span class="position-value">{{ modelPosition.x }}</span></div>
          <div>Y: <span class="position-value">{{ modelPosition.y }}</span></div>
          <div>Z: <span class="position-value">{{ modelPosition.z }}</span> <span class="highlight">(固定)</span></div>
        </div>
      </div>
      
      <div class="control-group">
        <h3>相机控制</h3>
        <p>左键拖动: 旋转视角</p>
        <p>右键拖动: 平移视角</p>
        <p>滚轮: 缩放</p>
      </div>
      
      <div class="instructions">
        <h3>使用说明</h3>
        <p>1. 从上方选择要加载的模型类型</p>
        <p>2. 在画布上<span class="highlight">点击并拖动鼠标</span>来移动模型</p>
        <p>3. 使用<span class="highlight">滑块</span>调整模型大小</p>
        <p>4. 使用鼠标<span class="highlight">右键拖动</span>来移动相机视角</p>
        <p>5. 使用<span class="highlight">滚轮</span>缩放场景</p>
        <p>6. 点击"<span class="highlight">重置位置</span>"将模型放回中心</p>
      </div>
    </div>
  </div>
</template>

<style scoped>
.container {
  display: flex;
  flex: 1;
  min-height: 0;
  height: 100vh;
}

.canvas-container {
  width:1200px;
  position: relative;
}

.three-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.controls-panel {
  width: 320px;
  background: rgba(0, 0, 0, 0.5);
  padding: 20px;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
  overflow-y: auto;
}

.control-group {
  margin-bottom: 20px;
  background: rgba(255, 255, 255, 0.05);
  padding: 15px;
  border-radius: 8px;
}

h3 {
  margin-top: 0;
  color: #4cc9f0;
  border-bottom: 1px solid rgba(76, 201, 240, 0.3);
  padding-bottom: 8px;
}

.btn {
  background: #4cc9f0;
  color: #0a2c3d;
  border: none;
  padding: 10px 15px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
  margin: 5px;
  transition: all 0.3s;
}

.btn:hover {
  background: #2fb5e0;
  box-shadow: 0 0 10px rgba(76, 201, 240, 0.7);
}

.position-display {
  background: rgba(0, 0, 0, 0.3);
  padding: 12px;
  border-radius: 4px;
  margin-top: 15px;
  font-family: monospace;
  font-size: 1.1rem;
}

.position-value {
  color: #4cc9f0;
  font-weight: bold;
}

.instructions {
  background: rgba(249, 217, 119, 0.1);
  padding: 15px;
  border-radius: 8px;
  border-left: 4px solid #f9d977;
  margin-top: 20px;
}

.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  flex-direction: column;
}

.spinner {
  width: 50px;
  height: 50px;
  border: 5px solid rgba(76, 201, 240, 0.3);
  border-radius: 50%;
  border-top-color: #4cc9f0;
  animation: spin 1s ease-in-out infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.loading-text {
  margin-top: 15px;
  color: #4cc9f0;
  font-size: 1.2rem;
}

.model-selector {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 10px;
}

.model-btn {
  flex: 1;
  min-width: 120px;
  background: #6a4ca3;
}

.model-btn:hover {
  background: #8a6cbf;
}

.highlight {
  color: #f9d977;
  font-weight: bold;
}
</style>